
#include "nane/core/crt/ModuleManagerImpl_.h"

#include <algorithm>

extern "C"
{
    typedef const nane::ModuleInfo* (*TGetModuleInfoRoutine)(nane::Context*);
}

namespace nane
{
    ////////////////////////////////////////////////////////////////////////////////////////////////
    static const char c_getInfoRoutine[] = "GetModuleInfo";
    ////////////////////////////////////////////////////////////////////////////////////////////////
    ModuleManager::Implementation::Implementation()
    {

    }
    ////////////////////////////////////////////////////////////////////////////////////////////////
    ModuleManager::Implementation::~Implementation()
    {
        modules.clear();
    }
    ////////////////////////////////////////////////////////////////////////////////////////////////
    bool ModuleManager::Implementation::Initialize()
    {
        return true;
    }
    ////////////////////////////////////////////////////////////////////////////////////////////////
    void ModuleManager::Implementation::Shutdown()
    {
        
    }
    ////////////////////////////////////////////////////////////////////////////////////////////////
    bool ModuleManager::Implementation::RegisterStaticModule( const ModuleInfo* _moduleInfo )
    {
        if( _moduleInfo == NULL )
        {
            return false;
        }
        TModuleImplVector::iterator it_find 
                = std::find_if(modules.begin(), modules.end(), FindModule(_moduleInfo->implementationName));
        if( it_find != modules.end() )
        {
            return false;
        }
        Module* module = new Module(this, ModuleHandle::s_staticHandle, _moduleInfo, _moduleInfo->implementationName);
        modules.push_back(ModulePtr(module));
        return true;
        
    }
    ////////////////////////////////////////////////////////////////////////////////////////////////
    IModule* ModuleManager::Implementation::LoadModule( const char* _moduleName )
    {
        ModulePtr modulePtr = NullPtr;
        TModuleImplVector::iterator it_find 
                = std::find_if(modules.begin(), modules.end(), FindModule(_moduleName));
        if( it_find != modules.end() )
        {
            modulePtr = (*it_find);
        }
        else
        {
            const ModuleInfo* moduleInfo = NULL;
            ModuleHandle* moduleHandle = DynamicModule::LoadModule(_moduleName);
            TGetModuleInfoRoutine pGetModuleInfoRoutine =
                    reinterpret_cast<TGetModuleInfoRoutine>(DynamicModule::GetFunction(moduleHandle, c_getInfoRoutine));
            if( pGetModuleInfoRoutine != NULL )
            {
                moduleInfo = pGetModuleInfoRoutine(m_context);
            }
            if( moduleInfo != NULL )
            {
                modulePtr = ModulePtr(new Module(this, moduleHandle, moduleInfo, _moduleName));
                modules.push_back(modulePtr);
            }
            else
            {
                DynamicModule::UnloadModule(moduleHandle);
            }
        }
        return modulePtr.Get();
        
    }
    ////////////////////////////////////////////////////////////////////////////////////////////////
    IModule* ModuleManager::Implementation::GetModuleByInterface( const char* _interfaceName )
    {
        ModulePtr modulePtr = NullPtr;
        TModuleImplVector::iterator it_find 
                = std::find_if(modules.begin(), modules.end(), FindModuleInterface(_interfaceName));
        if( it_find != modules.end() )
        {
            modulePtr = (*it_find);
        }
        return modulePtr.Get();
    }
    ////////////////////////////////////////////////////////////////////////////////////////////////
    void ModuleManager::Implementation::ForeachModule( const char* _interfaceName, IModuleSystem::ModuleApplyBase* _functor )
    {
        for( TModuleImplVector::iterator it = modules.begin(), it_end = modules.end()
            ; it != it_end
            ; ++it )
        {
            ModulePtr modulePtr = (*it);
            if( std::strcmp(modulePtr->GetInfo()->interfaceName, _interfaceName) == 0 )
            {
                _functor->Apply(modulePtr.Get());
            }
        }        
    }
    ////////////////////////////////////////////////////////////////////////////////////////////////
    void ModuleManager::Implementation::Release( Module* _module )
    {
        if( _module->interface != ModuleHandle::s_staticHandle )
        {
            DynamicModule::UnloadModule(_module->interface);
        }
        delete _module;
    }
    ////////////////////////////////////////////////////////////////////////////////////////////////
}   // namespace nane
